package luke.media.video;

import luke.audio.analyzer.UniversalAudioDecoder;
import luke.audio.analyzer.SpectrumAnalyzer;
import luke.core.config.AppDataManager;
import luke.core.logging.LogUtil;
import luke.system.callback.ProgressCallback;

import java.io.File;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * 视频生成调度类，用于统一处理视频生成逻辑，包括分段并行处理
 * 调度器的作用是预处理和分配频带能量数据等，然后将数据分发给渲染器进行渲染
 *
 * ==================== 重要说明 ====================
 * 此类为视频生成调度器，职责包括：
 * 1. 预处理和分配频带能量数据等前期工作
 * 2. 进行for循环,进行频带能量切片,临时输出路径切片
 * 3. 并行new 几个视频渲染器
 * 4. 等待视频生成完毕
 * 5. 调用合并方法
 * 6. 调用音频叠加方法
 * =================================================
 */
public class VideoGenerationScheduler {
    // 统一帧率设置，避免硬编码
    private static final double DEFAULT_FPS = 30.0;
    
    /**
     * 获取并行处理数量
     * 非捐赠用户返回1，已捐赠用户根据CPU核心数返回合适的数量
     * 
     * @param isLongDuration 是否为长时长音频（大于1分钟）
     * @return 并行处理数量
     */
    private static int getParallelCount(boolean isLongDuration) {
        boolean isDonated = AppDataManager.getInstance().isDonated();
        
        // 非捐赠用户始终返回1
        if (!isDonated) {
            return 1;
        }
        
        // 捐赠用户且为长时长音频才启用并行处理
        if (isLongDuration) {
            // 直接返回CPU核心数量，不再限制最大并行数量
            return Runtime.getRuntime().availableProcessors();
        }
        
        // 捐赠用户但非长时长音频也返回1
        return 1;
    }
    
    /**
     * 创建并生成频谱视频
     * 
     * @param audioFilePath 音频文件路径
     * @param totalDuration 音频总时长（毫秒）
     * @param outputVideoPath 输出视频路径
     * @param width 视频宽度
     * @param height 视频高度
     * @param playlistContent 播放列表内容
     * @param videoTitle 视频标题
     * @param videoStyle 视频样式（"spectrum", "circular", "starlight"）
     * @param progressCallback 进度回调
     * @return 生成成功返回true，失败返回false
     */
    public static boolean generateSpectrumVideo(String audioFilePath, 
                                               int totalDuration, 
                                               String outputVideoPath, 
                                               int width, 
                                               int height, 
                                               List<String> playlistContent, 
                                               String videoTitle, 
                                               String videoStyle, 
                                               ProgressCallback progressCallback) {
        LogUtil.debug("VideoGenerationScheduler", "generateSpectrumVideo", 
            "开始生成频谱视频 - 样式: " + videoStyle + ", 时长: " + totalDuration + "ms");
        
        // 检查是否需要使用分段处理模式（已捐赠且音频总时长大于1分钟）
        boolean isLongDuration = totalDuration > 1 * 60 * 1000; // 1分钟
        
        // 使用统一方法获取并行处理数量
        int segmentCount = getParallelCount(isLongDuration);
        
        LogUtil.debug("VideoGenerationScheduler", "generateSpectrumVideo", 
            "并行处理检查 - 长时长: " + isLongDuration + ", 分段数量: " + segmentCount + ", 总时长: " + totalDuration + "ms");
        
        // 预计算频谱数据
        UniversalAudioDecoder.AudioData audioData = null;
        double[][] precomputedSpectrums = null;
        
        try {
            UniversalAudioDecoder decoder = new UniversalAudioDecoder();
            File audioFile = new File(audioFilePath);
            audioData = decoder.decodeAudioFile(audioFile);
            
            // 将多声道音频转换为单声道
            float[] audioSamples = audioData.data;
            if (audioData.channels > 1) {
                audioSamples = convertToMono(audioData.data, audioData.channels);
                LogUtil.debug("VideoGenerationScheduler", "generateSpectrumVideo", 
                    "音频数据已从 " + audioData.channels + " 声道转换为单声道");
            }
            
            // 初始化频谱分析器
            int fftSize = 2048; // FFT大小
            SpectrumAnalyzer spectrumAnalyzer = new SpectrumAnalyzer(audioData.sampleRate, fftSize);
            
            // 计算步长以控制频谱数据的密度
            int hopSize = (int) (audioData.sampleRate / DEFAULT_FPS); // 使用统一帧率计算步长
            
            // 预计算频谱数据
            precomputedSpectrums = spectrumAnalyzer.computeSpectrogram(audioSamples, hopSize);
            LogUtil.debug("VideoGenerationScheduler", "generateSpectrumVideo", 
                "预计算频谱数据完成，帧数: " + precomputedSpectrums.length);
                
            // 检查频谱数据是否有效
            if (precomputedSpectrums == null || precomputedSpectrums.length == 0) {
                LogUtil.error("VideoGenerationScheduler", "generateSpectrumVideo", "频谱数据为空或无效");
                return false;
            }
        } catch (Exception e) {
            LogUtil.error("VideoGenerationScheduler", "generateSpectrumVideo", "解码音频文件失败: " + e.getMessage());
            return false;
        }
        
        // 分割频谱数据
        List<double[][]> spectrumSegments = splitSpectrums(precomputedSpectrums, segmentCount);
        LogUtil.debug("VideoGenerationScheduler", "generateSpectrumVideo", "频谱数据分割完成，段数: " + spectrumSegments.size());
        
        // 检查分割后的频谱数据是否有效
        if (spectrumSegments.isEmpty()) {
            LogUtil.error("VideoGenerationScheduler", "generateSpectrumVideo", "频谱数据分割后为空");
            return false;
        }
        
        // 获取临时目录
        File tempDir = AppDataManager.getInstance().getTempDirectory().toFile();
        File outputFile = new File(outputVideoPath);
        String fileName = outputFile.getName();
        int lastDotIndex = fileName.lastIndexOf('.');
        String baseName = lastDotIndex > 0 ? fileName.substring(0, lastDotIndex) : fileName;
        String extension = lastDotIndex > 0 ? fileName.substring(lastDotIndex) : ".mp4";
        
        // 创建分段输出路径
        List<String> segmentOutputPaths = new ArrayList<>();
        for (int i = 0; i < segmentCount; i++) {
            // 使用MKV格式作为无损中间格式
            String segmentOutputPath = new File(tempDir, baseName + "_segment_" + i + ".mkv").getAbsolutePath();
            segmentOutputPaths.add(segmentOutputPath);
        }
        
        LogUtil.debug("VideoGenerationScheduler", "generateSpectrumVideo", "分段数量: " + segmentCount + ", 临时目录: " + tempDir.getAbsolutePath());
        
        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(segmentCount);
        List<Future<Boolean>> futures = new ArrayList<>();
        
        // 创建用于跟踪进度的数组
        final int[] processedFrames = new int[segmentCount];
        final int[] totalFrames = new int[segmentCount];
        
        // 初始化总帧数
        for (int i = 0; i < segmentCount; i++) {
            totalFrames[i] = spectrumSegments.get(i).length;
        }
        
        // 计算每个片段的时长（毫秒）
        int[] segmentDurations = new int[segmentCount];
        int totalAssignedDuration = 0;
        for (int i = 0; i < segmentCount - 1; i++) {
            segmentDurations[i] = totalDuration / segmentCount;
            totalAssignedDuration += segmentDurations[i];
        }
        // 最后一个片段分配剩余的时长，确保总时长准确
        segmentDurations[segmentCount - 1] = totalDuration - totalAssignedDuration;
        
        // 并行创建和执行视频渲染器
        for (int i = 0; i < segmentCount; i++) {
            final int segmentIndex = i;
            final double[][] segmentSpectrums = spectrumSegments.get(i);
            final String segmentOutputPath = segmentOutputPaths.get(i);
            final int segmentDuration = segmentDurations[segmentIndex]; // 使用计算出的片段时长
            
            // 检查当前片段的频谱数据是否有效
            if (segmentSpectrums == null || segmentSpectrums.length == 0) {
                LogUtil.warn("VideoGenerationScheduler", "generateSpectrumVideo", 
                    "片段 " + segmentIndex + " 的频谱数据为空，跳过处理");
                continue;
            }
            
            Future<Boolean> future = executor.submit(() -> {
                try {
                    LogUtil.debug("VideoGenerationScheduler", "generateSpectrumVideo", 
                        "开始生成片段 " + segmentIndex + ", 输出路径: " + segmentOutputPath + ", 时长: " + segmentDuration + "ms");
                    
                    boolean segmentResult = false;
                    // 统一帧率设置
                    double fps = DEFAULT_FPS;
                    switch (videoStyle) {
                        case "spectrum":
                            SpectrumVideoGenerator spectrumGenerator = new SpectrumVideoGenerator(
                                segmentOutputPath,
                                width,
                                height,
                                playlistContent,
                                videoTitle,
                                fps, // 传入帧率
                                64 // 传入频段数量
                            );
                            spectrumGenerator.setPrecomputedSpectrums(segmentSpectrums);
                            segmentResult = spectrumGenerator.generateVideoWithSpectrum(
                                segmentDuration, // 使用正确的片段时长
                                new ProgressCallback() {
                                    @Override
                                    public void onProgress(String message, double progress) {
                                        // 更新已处理帧数
                                        processedFrames[segmentIndex] = (int) (totalFrames[segmentIndex] * progress / 100);
                                        
                                        // 计算总进度（第一阶段占总进度的0-33%）
                                        int totalProcessed = 0;
                                        int grandTotal = 0;
                                        for (int j = 0; j < segmentCount; j++) {
                                            totalProcessed += processedFrames[j];
                                            grandTotal += totalFrames[j];
                                        }
                                        
                                        // 更新总体进度（第一阶段）
                                        if (progressCallback != null && grandTotal > 0) {
                                            // 确保进度不超过33%
                                            int overallProgress = Math.min(33, (int) ((double) totalProcessed / grandTotal * 33));
                                            progressCallback.onProgress("正在生成视频片段..." , overallProgress);
                                        }
                                    }
                                }
                            );
                            break;
                        case "circular":
                            CircularSpectrumVideoGenerator circularGenerator = new CircularSpectrumVideoGenerator(
                                segmentOutputPath,
                                width,
                                height,
                                playlistContent,
                                videoTitle,
                                fps, // 传入帧率
                                128 // 传入频段数量
                            );
                            circularGenerator.setPrecomputedSpectrums(segmentSpectrums);
                            segmentResult = circularGenerator.generateVideoWithCircularSpectrum(
                                segmentDuration, // 使用正确的片段时长
                                new ProgressCallback() {
                                    @Override
                                    public void onProgress(String message, double progress) {
                                        // 更新已处理帧数
                                        processedFrames[segmentIndex] = (int) (totalFrames[segmentIndex] * progress / 100);
                                        
                                        // 计算总进度（第一阶段占总进度的0-33%）
                                        int totalProcessed = 0;
                                        int grandTotal = 0;
                                        for (int j = 0; j < segmentCount; j++) {
                                            totalProcessed += processedFrames[j];
                                            grandTotal += totalFrames[j];
                                        }
                                        
                                        // 更新总体进度（第一阶段）
                                        if (progressCallback != null && grandTotal > 0) {
                                            // 确保进度不超过33%
                                            int overallProgress = Math.min(33, (int) ((double) totalProcessed / grandTotal * 33));
                                            progressCallback.onProgress("正在生成视频片段..." , overallProgress);
                                        }
                                    }
                                }
                            );
                            break;
                        case "starlight":
                            SpectrumStarlightVideoGenerator starlightGenerator = new SpectrumStarlightVideoGenerator(
                                segmentOutputPath,
                                width,
                                height,
                                playlistContent,
                                videoTitle,
                                fps, // 传入帧率
                                64 // 传入频段数量
                            );
                            // 设置全局帧索引偏移量
                            int globalFrameOffset = 0;
                            for (int k = 0; k < segmentIndex; k++) {
                                globalFrameOffset += spectrumSegments.get(k).length;
                            }
                            starlightGenerator.setGlobalFrameOffset(globalFrameOffset);
                            
                            starlightGenerator.setPrecomputedSpectrums(segmentSpectrums);
                            segmentResult = starlightGenerator.generateVideoWithSpectrum(
                                segmentDuration, // 使用正确的片段时长
                                new ProgressCallback() {
                                    @Override
                                    public void onProgress(String message, double progress) {
                                        // 更新已处理帧数
                                        processedFrames[segmentIndex] = (int) (totalFrames[segmentIndex] * progress / 100);
                                        
                                        // 计算总进度（第一阶段占总进度的0-33%）
                                        int totalProcessed = 0;
                                        int grandTotal = 0;
                                        for (int j = 0; j < segmentCount; j++) {
                                            totalProcessed += processedFrames[j];
                                            grandTotal += totalFrames[j];
                                        }
                                        
                                        // 更新总体进度（第一阶段）
                                        if (progressCallback != null && grandTotal > 0) {
                                            // 确保进度不超过33%
                                            int overallProgress = Math.min(33, (int) ((double) totalProcessed / grandTotal * 33));
                                            progressCallback.onProgress("正在生成视频片段..." , overallProgress);
                                        }
                                    }
                                }
                            );
                            break;
                        default:
                            LogUtil.error("VideoGenerationScheduler", "generateSpectrumVideo", "未知的视频样式: " + videoStyle);
                            return false;
                    }
                    
                    LogUtil.debug("VideoGenerationScheduler", "generateSpectrumVideo", 
                        "片段 " + segmentIndex + " 生成完成，结果: " + segmentResult);
                    return segmentResult;
                } catch (Exception e) {
                    LogUtil.error("VideoGenerationScheduler", "generateSpectrumVideo", 
                        "生成片段 " + segmentIndex + " 时出错: " + e.getMessage());
                    return false;
                }
            });
            futures.add(future);
        }
        
        // 检查是否有有效的任务
        if (futures.isEmpty()) {
            LogUtil.error("VideoGenerationScheduler", "generateSpectrumVideo", "没有有效的视频生成任务");
            return false;
        }
        
        // 等待所有片段生成完成
        boolean allSuccess = true;
        for (int i = 0; i < futures.size(); i++) {
            try {
                boolean success = futures.get(i).get();
                if (!success) {
                    allSuccess = false;
                    LogUtil.error("VideoGenerationScheduler", "generateSpectrumVideo", 
                        "片段 " + i + " 生成失败");
                } else {
                    LogUtil.debug("VideoGenerationScheduler", "generateSpectrumVideo", 
                        "片段 " + i + " 生成成功");
                }
            } catch (Exception e) {
                LogUtil.error("VideoGenerationScheduler", "generateSpectrumVideo", 
                    "等待片段 " + i + " 完成时出错: " + e.getMessage());
                allSuccess = false;
            }
        }
        
        // 关闭线程池
        executor.shutdown();
        try {
            if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
        }
        
        if (!allSuccess) {
            LogUtil.error("VideoGenerationScheduler", "generateSpectrumVideo", 
                "一个或多个片段生成失败");
            return false;
        }
        
        // 合并所有片段并添加音频轨道（第二和第三阶段占总进度的33-100%）
        if (progressCallback != null) {
            progressCallback.onProgress("正在合并视频片段并添加音频...", 33);
        }
        
        LogUtil.debug("VideoGenerationScheduler", "generateSpectrumVideo", "开始调用合并视频片段并添加音频轨道");
        // 修改调用，传递音频文件路径而不是AudioData对象
        boolean mergeResult = SegmentedVideoProcessor.mergeVideoSegmentsWithAudio(segmentOutputPaths, outputVideoPath, audioFilePath, new ProgressCallback() {
            @Override
            public void onProgress(String message, double progress) {
                // 合并和音频添加阶段占总进度的33-100%
                if (progressCallback != null) {
                    int overallProgress = 33 + (int) (progress * 67 / 100);
                    progressCallback.onProgress(message, overallProgress);
                }
            }
        });
        
        if (!mergeResult) {
            LogUtil.error("VideoGenerationScheduler", "generateSpectrumVideo", 
                "合并视频片段并添加音频轨道失败");
            return false;
        }
        
        LogUtil.debug("VideoGenerationScheduler", "generateSpectrumVideo", "合并视频片段并添加音频轨道成功");
        
        // 清理临时文件
        cleanupTempFiles(segmentOutputPaths);
        
        LogUtil.debug("VideoGenerationScheduler", "generateSpectrumVideo", "频谱视频生成完成");
        if (progressCallback != null) {
            progressCallback.onProgress("视频生成完成", 100);
        }
        return true;
    }
    
    /**
     * 分割频谱数据
     */
    private static List<double[][]> splitSpectrums(double[][] spectrums, int segmentCount) {
        List<double[][]> segments = new ArrayList<>();
        
        if (segmentCount <= 1) {
            // 不分段的情况
            segments.add(spectrums);
            return segments;
        }
        
        int totalFrames = spectrums.length;
        int framesPerSegment = totalFrames / segmentCount;
        
        for (int i = 0; i < segmentCount; i++) {
            int startFrame = i * framesPerSegment;
            int endFrame = (i == segmentCount - 1) ? totalFrames : (i + 1) * framesPerSegment;
            
            int segmentLength = endFrame - startFrame;
            double[][] segment = new double[segmentLength][];
            for (int j = 0; j < segmentLength; j++) {
                segment[j] = spectrums[startFrame + j];
            }
            segments.add(segment);
        }
        
        return segments;
    }
    
    /**
     * 将多声道音频数据转换为单声道
     */
    private static float[] convertToMono(float[] audioData, int channels) {
        if (channels <= 1) {
            return audioData;
        }
        
        int monoLength = audioData.length / channels;
        float[] monoData = new float[monoLength];
        
        for (int i = 0; i < monoLength; i++) {
            float sum = 0;
            for (int j = 0; j < channels; j++) {
                sum += audioData[i * channels + j];
            }
            monoData[i] = sum / channels; // 平均值混合
        }
        
        return monoData;
    }
    
    /**
     * 清理临时文件
     */
    private static void cleanupTempFiles(List<String> segmentOutputPaths) {
        try {
            LogUtil.debug("VideoGenerationScheduler", "cleanupTempFiles", "开始清理临时文件");
            
            for (String segmentPath : segmentOutputPaths) {
                File segmentFile = new File(segmentPath);
                if (segmentFile.exists()) {
                    if (segmentFile.delete()) {
                        LogUtil.debug("VideoGenerationScheduler", "cleanupTempFiles", "已删除临时文件: " + segmentPath);
                    } else {
                        LogUtil.warn("VideoGenerationScheduler", "cleanupTempFiles", "无法删除临时文件: " + segmentPath);
                    }
                }
            }
        } catch (Exception e) {
            LogUtil.error("VideoGenerationScheduler", "cleanupTempFiles", "清理临时文件时出错: " + e.getMessage());
        }
    }
}